using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using MokkAnnotator;
using WeifenLuo.WinFormsUI.Docking;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using MokkAnnotator.MkaCommon;
using MokkAnnotator.MkaDockToolkit;
using MokkAnnotator.MkaImageProcess;
using System.IO;
using Microsoft.Win32;
using System.Xml;
using MokkAnnotator.MkaDocToolkit.Xml;
using MokkAnnotator.MkaWindow;
using MokkAnnotator.MkaToolsData;
using MySql.Data.MySqlClient;
using System.Runtime.InteropServices;
using Microsoft.Ink;
using System.Collections;

namespace MokkAnnotator.MkaDrawTools
{
    public enum InkCommentMode
    {
        Ink,
        PolygonSelection,
        InkMovement,
        DeleteStroke
    }
    partial class MkaDocument : DockContent
    {
        static log4net.ILog _log = MkaDefine.Logger;    // log manager   

        // create array of drawing tools
        static Tool[] tools = new Tool[(int)ToolType.ToolsCount] {
                                            new ToolPointer(),
                                            new ToolRectangle(),
                                            new ToolEllipse(),
                                            new ToolPolygon()};

        // Declare constant for the size of the border around selected strokes
        private const int SelectedInkWidthIncrease = 105;

        private MkaFrmAnnotator _owner;
        private UndoManager _undoManager;

        private Bitmap _image;                          // glass's image
        private Bitmap _bkImg;
        private int _width;
        private int _height;
        private Rectangle _rect;

        private float _zoom;                            //Zoom scale
        private bool _dirty = false;

        private MkaGlassInfo _glassInfo;                //Glass information
        private MokkanList _mokkanList;                 //List of draw objects

        //Copy item list   
        private List<DrawObject> _copyItems = new List<DrawObject>();
        private int _lengthSelectedText;                //Length of Selected text in last textbox


        private bool _isCopy = true;
        private int _continousPaste = 0;

        private ToolType _activeTool;                   //Active drawing tool        
        private DisplayType _activeDisplay;             //Active display type   

        private RichTextBox m_lastTextBoxFocused = null; //Last focused textbox
        private int _startPosition;                     //Start position of text in the last focused textbox

        private bool _AddText = false;                  //Check button add comment is pressed
        private TextFormat _textFormat;                 //Add format control for comment 
        public Tracker m_CSharpTracker;                        //Tracker of RichTextBox 
        // Comment TextBox
        public List<TransparentRichTextBox> m_rtxtListComment = new List<TransparentRichTextBox>();


        private InkCollector _inkCollectComment;        //This is to handle ink draw


        #region//////////////////////////////////////////////CONSTANT///////////////////////////////////////
        private const float MediumInkWidth = 100;       //The width of ink when draw
        // Declare constant for the size of the hit test circle radius.
        // Note that this constant is in high metric units (1 unit = .01mm)
        private const float HitTestRadius = 60;

        // Declare constant for the spacing between lasso points
        private const int DotSpacing = 7;

        // Declare constant for the size of a lasso point
        private const int DotSize = 6;

        // The index for the x and y packet values.  This index is used
        // to retrieve the lasso point data in the Packets event handler.
        private const int XPacketIndex = 0;
        private const int YPacketIndex = 1;

        // Declare constant for the padding size of the rectangle that bounds
        // the selected strokes.
        private const int SelectionRectBuffer = 8;

        // Declare constant for the lasso hit test percent (specifies how much
        // of the stroke must fall within the lasso in order to be selected).
        private const float LassoPercent = 1;
        #endregion ////////////////////////////////////////////CONSTANT/////////////////////////////////////

        #region//////////////////////////////////////////////PROPERTY///////////////////////////////////////
        // Check event if it was added. This is to make sure that don't have 2 same events added to an object
        private int eventCheck = 0;

        //Trace previous point to clear when having new lasso
        private Point mPreviousPoint = Point.Empty;

        // They are modes when using ink to draw comment.
        // They are corresspoding to the menu item strip in ink menustrip button.
        // They are used when button on MkaFramAnnotator is clicked
        private bool inkmenuitem = false;
        private bool selectmenuitem = false;
        private bool deletemenueitem = false;
        private bool copymenueitem = false;

        // The current application mode:  inking, selecting, or moving the selection
        private InkCommentMode inkCommentMode = InkCommentMode.Ink;

        //Strokes are deleted 
        public Stack<Ink> m_inkForDeletedStrokes = new Stack<Ink>();
        // The points in the selection lasso
        private ArrayList lassoPoints = null;

        // The coordinates of the last lasso point drawn (empty if no dot has been drawn)
        private Point lastDrawnLassoDot = Point.Empty;

        // Declare the colors used in the selection lasso
        private Color dotEdgeColor = Color.White;
        private Color dotColor = SystemColors.Highlight;
        private Color connectorColor = Color.Black;

        // The strokes that have been selected by the lasso
        private Strokes selectedStrokes = null;

        // Declare the pens used to draw the selection lasso
        private Pen connectorPen = null;
        private Pen dotEdgePen = null;
        private Pen dotPen = null;

        // The rectangle that bounds the selected strokes
        private Rectangle selectionRect = Rectangle.Empty;

        // The array of rectangle selection handles
        private PictureBox[] selectionHandles;
        // The location where the move started (used when moving selected strokes)
        private Point startMoveLocation = Point.Empty;

        #endregion/////////////////////////////////////PROPERTY///////////////////////////////////////////////

        #region/////////////////////////////////////SET/GET/////////////////////////////////////////////////
        //Set, Get for _inkOverLayDraw atribution 
        public InkCollector InkCollectComment
        {
            get { return _inkCollectComment; }
            set { _inkCollectComment = value; }
        }

        //Set, Get for _rtxtListComment atribution 
        public List<TransparentRichTextBox> RichTextListComment
        {
            get { return m_rtxtListComment; }
            set { m_rtxtListComment = value; }
        }

        //Set, Get for _lastTextBoxFocused atribution 
        public RichTextBox LastTextBoxFocused
        {
            get { return m_lastTextBoxFocused; }
            set { m_lastTextBoxFocused = value; }
        }

        //Set, Get for _startPosition atribution 
        public int StartPositionSelectedText
        {
            get { return _startPosition; }
            set { _startPosition = value; }
        }

        //Set, Get for _lengthSelectedText atribution 
        public int LengthSelectedText
        {
            get { return _lengthSelectedText; }
            set { _lengthSelectedText = value; }
        }

        //Set, Get for _textFormat atribution 
        public TextFormat SetGetTextFormat
        {
            get { return _textFormat; }
            set { _textFormat = value; }
        }

        //Set, Get for _AddText atribution 
        public bool AddText
        {
            get { return _AddText; }
            set { _AddText = value; }
        }

        //Set, Get for INKMENUITEM atribution 
        public bool INKMENUITEM
        {
            get { return inkmenuitem; }
            set { inkmenuitem = value; }
        }
        //Set, Get for DELETEMENUITEM atribution
        public bool DELETEMENUITEM
        {
            get { return deletemenueitem; }
            set { deletemenueitem = value; }
        }

        //Set, Get for SELECTMENUITEM atribution
        public bool SELECTMENUITEM
        {
            get { return selectmenuitem; }
            set { selectmenuitem = value; }
        }

        //Set, Get for _selectStroke atribution
        public bool COPYMENUITEM
        {
            get { return copymenueitem; }
            set { copymenueitem = value; }
        }
        #endregion/////////////////////////////////////SET/GET/////////////////////////////////////////////////


        #region Properties

        /// <summary>
        /// Bat information
        /// </summary>
        public MkaBatInfo BatInfo
        {
            get { return _glassInfo.BatInfo; }
            set { _glassInfo.BatInfo = value; }
        }

        /// <summary>
        /// Glass information
        /// </summary>
        public MkaGlassInfo GlassInfo
        {
            get { return _glassInfo; }
            set { _glassInfo = value; }
        }

        /// <summary>
        /// Document filename
        /// </summary>
        public String FileName
        {
            get { return GlassInfo.GlassFileName; }
        }

        /// <summary>
        /// Document file fullname
        /// </summary>
        public String FileFullName
        {
            get { return GlassInfo.GlassFilePath; }
        }

        /// <summary>
        /// Glass's image
        /// </summary>
        public Bitmap Image
        {
            get { return _image; }
            set { _image = value; }
        }

        /// <summary>
        /// Image's filename
        /// </summary>
        public string GlassImage
        {
            get { return GlassInfo.ImageFilePath; }
            set
            {
                // change display image                      
                this._image = new Bitmap(Bitmap.FromFile(value));
                this._bkImg = (Bitmap)_image.Clone();

                // update glass information
                GlassInfo.ImageFilePath = value;
                GlassInfo.ImageFileName = Path.GetFileName(value);
                GlassInfo.Width = _image.Width;
                GlassInfo.Height = _image.Height;

                // update size of window
                UpdateSize();
            }
        }

        /// <summary>
        /// Width of image
        /// </summary>
        public int ImageWidth
        {
            get { return _width; }
        }

        /// <summary>
        /// Height of image
        /// </summary>
        public int ImageHeight
        {
            get { return _height; }
        }

        /// <summary>
        /// Boundary rectangle of image
        /// </summary>
        public Rectangle ImageRectangle
        {
            get { return _rect; }
        }

        /// <summary>
        /// Zoom scale
        /// </summary>
        public int Zoom
        {
            get { return (int)(_zoom * 100); }
            set { _zoom = (float)(value / 100); }
        }

        /// <summary>
        /// Active drawing tool.
        /// </summary>
        public ToolType ActiveTool
        {
            get { return _activeTool; }
            set { _activeTool = value; _owner.ToolbarChangeCommand(value); }
        }

        /// <summary>
        /// Active display type
        /// </summary>
        public DisplayType ActiveDisplay
        {
            get { return _activeDisplay; }
            set { _activeDisplay = value; }
        }

        /// <summary>
        /// List of graphics objects.
        /// </summary>
        public MokkanList MokkanList
        {
            get { return _mokkanList; }
            set
            {
                _mokkanList = value;
                _undoManager.MokkanList = value;
            }
        }

        /// <summary>
        /// Return True if Undo operation is possible
        /// </summary>
        public bool CanUndo
        {
            get
            {
                if (_undoManager != null)
                {
                    return _undoManager.CanUndo;
                }

                return false;
            }
        }

        /// <summary>
        /// Return True if Redo operation is possible
        /// </summary>
        public bool CanRedo
        {
            get
            {
                if (_undoManager != null)
                {
                    return _undoManager.CanRedo;
                }

                return false;
            }
        }

        /// <summary>
        /// Dirty property (true when document has unsaved changes).
        /// </summary>
        public bool Dirty
        {
            get
            {
                return _dirty;
            }
            set
            {
                _dirty = value;
                UpdateCaption();
            }
        }

        /// <summary>
        /// Used to fix bug open dialog -> double click
        /// </summary>
        public bool ReOpen { get; set; }

        #endregion

        /// <summary>
        /// Constructor
        /// </summary>
        public MkaDocument(MkaFrmAnnotator owner)
        {
            // Init components
            InitializeComponent();
            _owner = owner;

            // Init members
            this._image = null;
            this._width = 0;
            this._height = 0;
            this._glassInfo = new MkaGlassInfo();
            this._mokkanList = new MokkanList();
            this.ReOpen = false;
            m_CSharpTracker = new Tracker();
            _textFormat = new TextFormat();


            lassoPoints = new ArrayList();
            selectedStrokes = null;
            selectionHandles = new PictureBox[] { leftTopHandle, centerTopHandle, rightTopHandle, leftCenterHandle, rightCenterHandle, leftBottomHandle, centerBottomHandle, rightBottomHandle };

            // Create the pens used to draw the lasso selection
            connectorPen = new Pen(connectorColor);     // Pen used to draw dotted lasso connector line
            connectorPen.DashStyle = DashStyle.Dash;
            dotEdgePen = new Pen(dotEdgeColor);         // Pen used to draw the outer edge of the lasso dot
            dotPen = new Pen(dotColor);                 // Pen used to draw the center of the lasso dot



            this.MouseWheel += new MouseEventHandler(DocumentArea_MouseWheel);

            // set default tool
            _activeTool = ToolType.Pointer;

            // Create undo manager
            _undoManager = new UndoManager(_mokkanList);

            // Configure form's style
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer | ControlStyles.ResizeRedraw, true);
            //SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true);
            this.AutoScroll = true;
            this.Scroll += new ScrollEventHandler(scroll_EventHandler);
            this.MouseWheel += new MouseEventHandler(scroll_MouseWheel);


            // Init zoom 
            this._zoom = 1;
        }

        /// <summary>
        /// Renew document when overwrite
        /// </summary>
        /// <param name="glassInfo"></param>
        public void ReNew(MkaGlassInfo glassInfo)
        {
            // Init members                                    
            this._glassInfo = glassInfo;
            this._mokkanList = new MokkanList();
            this._mokkanList.KaishiRBangou = glassInfo.KaishiRBangou;
            this.GlassImage = glassInfo.ImageFilePath;

            // set default tool
            _activeTool = ToolType.Pointer;

            // Create undo manager
            _undoManager = new UndoManager(_mokkanList);
            Dirty = false;
            ReOpen = false;

            // Init zoom scale
            ZoomToWindow();
        }

        /// <summary>
        /// Update size of window
        /// </summary>
        private void UpdateSize()
        {
            // update size of image
            _width = _image.Width;
            _height = _image.Height;
            _rect = new Rectangle(0, 0, _width, _height);

            // update size of scroll bar
            this.AutoScrollMinSize = new Size((int)(_width * _zoom), (int)(_height * _zoom));

            // redraw
            this.Invalidate();
        }

        #region Zoom Processing
        /// <summary>
        /// Zoom image
        /// </summary>
        /// <param name="zoom">zoom scale</param>
        public void ZoomImage(float zoom)
        {
            // update zoom scale
            this._zoom = zoom;

            // update size after zoom
            UpdateZoom();
        }

        /// <summary>
        /// Update size after zoom
        /// </summary>
        public void UpdateZoom()
        {
            DrawObject.Ratio = this._zoom;

            _owner.DocAreaZoomChange();

            // update size of scroll bar
            this.AutoScrollMinSize = new Size((int)(_width * _zoom), (int)(_height * _zoom));

            zoomInkUpdate();

            // redraw
            this.Invalidate();
        }

        /// <summary>
        /// Expand image
        /// </summary>
        public void ZoomIn()
        {
            // enlarge by next scale between 0.25 and 5 times
            if (_zoom < 5)
            {
                for (int i = 0; i < MkaDefine.Zooms.Length; i++)
                {
                    if (this._zoom < (float)MkaDefine.Zooms[i] / 100)
                    {
                        _zoom = (float)MkaDefine.Zooms[i] / 100;
                        break;
                    }
                }
            }
            else // otherwise, enlarge by unit of 1
                _zoom = (int)_zoom + 1f;

            // maximum 10 times
            if (_zoom > 10)
                _zoom = 10;

            // update size after zoom
            UpdateZoom();
        }

        /// <summary>
        /// Zoom to fix window size
        /// </summary>
        public void ZoomToWindow()
        {
            // get scale to fix window size
            _zoom = Math.Min((float)this.Width / (_width + 2), (float)this.Height / (_height + 2));

            // update size after zoom
            UpdateZoom();
        }

        /// <summary>
        /// Zoom to original size
        /// </summary>
        public void ZoomToActual()
        {
            // update zoom scale
            this._zoom = 1f;

            // update size after zoom
            UpdateZoom();
        }

        /// <summary>
        /// Shrink image
        /// </summary>
        public void ZoomOut()
        {
            // Minimum 0.25 times
            if (_zoom == 0.25) return;

            // Shrink by previous scale between 0.25 and 6 times
            if (_zoom < 6)
            {
                for (int i = MkaDefine.Zooms.Length - 1; i >= 0; i--)
                {
                    if (this._zoom > (float)MkaDefine.Zooms[i] / 100)
                    {
                        _zoom = (float)MkaDefine.Zooms[i] / 100;
                        break;
                    }
                }
            }
            else if (_zoom > (int)_zoom)  // otherwise, shrink by unit of 1
                _zoom = (float)(int)_zoom;
            else
                _zoom -= 1f;

            // update size after zoom
            UpdateZoom();
        }

        /// <summary>
        /// Zoom when wheel mouse
        /// </summary>        
        private void DocumentArea_MouseWheel(object sender, MouseEventArgs e)
        {
            if (e.Delta == 0)
                return;

            if (Control.ModifierKeys != Keys.Control)
                return;

            if (e.Delta > 0)
                ZoomIn();
            else
                ZoomOut();
        }

        #endregion

        #region Rotate Processing

        /// <summary>
        /// Flip image
        /// </summary>
        public void RotateFlip()
        {
            // flip image
            this._image.RotateFlip(RotateFlipType.RotateNoneFlipY);

            // update size of window
            UpdateSize();
        }

        /// <summary>
        /// Mirror image
        /// </summary>
        public void RotateMirror()
        {
            // mirror image
            this._image.RotateFlip(RotateFlipType.RotateNoneFlipX);

            // update size of window
            UpdateSize();
        }

        /// <summary>
        /// Rotate image 180 degree
        /// </summary>
        public void Rotate180()
        {
            // 90 degree right rotate
            this._image.RotateFlip(RotateFlipType.Rotate180FlipNone);

            // update size of window
            UpdateSize();
        }

        /// <summary>
        /// Rotate to the right
        /// </summary>
        public void RotateRight()
        {
            // 90 degree right rotate
            this._image.RotateFlip(RotateFlipType.Rotate90FlipNone);

            // update size of window
            UpdateSize();
        }

        /// <summary>
        /// 
        /// </summary>
        public void RotateLeft()
        {
            // 90 degrees left rotate
            this._image.RotateFlip(RotateFlipType.Rotate270FlipNone);

            // update size of window
            UpdateSize();
        }

        /// <summary>
        /// Rotate 
        /// </summary>
        /// <param name="angle"></param>
        public void Rotate(double angle, Color fillColor, RotateType type)
        {
            this._owner.Cursor = System.Windows.Forms.Cursors.WaitCursor;
            if (type == RotateType.NearestNeighbor)
                _image = ImageRotate.RotateNearestNeighbor(_image, _rect, angle, fillColor);
            else if (type == RotateType.Bilinear)
                _image = ImageRotate.RotateBilinear(_image, _rect, angle, fillColor);
            else
                _image = ImageRotate.RotateBicubic(_image, _rect, angle, fillColor);

            // update size of window
            UpdateSize();
            this._owner.Cursor = System.Windows.Forms.Cursors.Default;
        }

        #endregion

        #region Image Processing

        /// <summary>
        /// Restore to original image
        /// </summary>
        public void ImageRestore()
        {
            this._owner.Cursor = System.Windows.Forms.Cursors.WaitCursor;
            _image.Dispose();
            _image = (Bitmap)_bkImg.Clone();
            UpdateSize();
            this._owner.Cursor = System.Windows.Forms.Cursors.Default;
        }

        /// <summary>
        /// Adjust brightness and contrast of image
        /// </summary>        
        public void ImageAdjustBrightnessContrast(int brightness, int contrast)
        {
            this._owner.Cursor = System.Windows.Forms.Cursors.WaitCursor;
            Bitmap tmp = ImageAdjustment.AdjustBrightnessContrast(_image, _rect, brightness, contrast);
            if (tmp != null)
            {
                _image.Dispose();
                _image = tmp;
            }

            Refresh();
            this._owner.Cursor = System.Windows.Forms.Cursors.Default;
        }

        /// <summary>
        /// Adjust hue, saturation and lightness of image
        /// </summary>        
        public void ImageAdjustHSL(int hue, int saturation, int lightness)
        {
            this._owner.Cursor = System.Windows.Forms.Cursors.WaitCursor;
            Bitmap tmp = ImageAdjustment.AdjustHSL(_image, _rect, hue, saturation, lightness);
            if (tmp != null)
            {
                _image.Dispose();
                _image = tmp;
            }
            Refresh();
            this._owner.Cursor = System.Windows.Forms.Cursors.Default;
        }

        #endregion Image Processing

        #region Other Functions

        /// <summary>
        /// Copied item count
        /// </summary>
        [DefaultValue(-1)]
        public int CopyCount { get; set; }

        /// <summary>
        /// Cut
        /// </summary>
        public void Cut()
        {
            if (!this.IsActivated) return;

            // copy items
            Copy();

            _isCopy = false;

            // delete cut items            
            CommandDelete command = new CommandDelete(_mokkanList);

            if (_mokkanList.DeleteSelection())
            {
                SetDirty();
                Refresh();
                AddCommandToHistory(command);
            }
        }

        /// <summary>
        /// Copy
        /// </summary>
        public void Copy()
        {
            if (!this.IsActivated) return;

            _isCopy = true;
            _copyItems.Clear();
            _copyItems = _mokkanList.SelectedCloneObjects;
            CopyCount = _copyItems.Count;
            _continousPaste = 1;

            SetDirty();
            Refresh();
        }

        /// <summary>
        /// Paste
        /// </summary>
        public void Paste()
        {
            if (!this.IsActivated) return;

            _mokkanList.UnselectAll();
            List<DrawObject> pasteItems = new List<DrawObject>();
            DrawObject pasteObj;
            foreach (DrawObject obj in _copyItems)
            {
                pasteObj = obj.Clone();
                pasteObj.ID = pasteObj.GetHashCode();
                if (_isCopy)
                    pasteObj.Move(10 * _continousPaste, 10 * _continousPaste);
                pasteObj.MokkanInfo.RBangou = _mokkanList.GetMaxRBangou() + 1;
                pasteObj.Selected = true;
                pasteItems.Add(pasteObj);
                _mokkanList.Add(pasteObj);
            }
            _isCopy = true;

            CommandAdd command = new CommandAdd(pasteItems);
            SetDirty();
            Refresh();
            AddCommandToHistory(command);
            _continousPaste++;
        }

        /// <summary>
        /// Delete
        /// </summary>
        public void Delete()
        {
            if (!this.IsActivated) return;

            CommandDelete command = new CommandDelete(MokkanList);

            if (MokkanList.DeleteSelection())
            {
                SetDirty();
                Refresh();
                AddCommandToHistory(command);
            }
        }

        /// <summary>
        /// Delete all
        /// </summary>
        public void DeleteAll()
        {
            if (!this.IsActivated) return;

            CommandDeleteAll command = new CommandDeleteAll(MokkanList);

            if (MokkanList.Clear())
            {
                SetDirty();
                Refresh();
                AddCommandToHistory(command);
            }
        }

        /// <summary>
        /// Move forward
        /// </summary>
        public void MoveFront()
        {
            if (!this.IsActivated) return;

            if (MokkanList.MoveSelectionToFront())
            {
                SetDirty();
                Refresh();
            }
        }

        /// <summary>
        /// Move backward
        /// </summary>
        public void MoveBack()
        {
            if (!this.IsActivated) return;

            if (MokkanList.MoveSelectionToBack())
            {
                SetDirty();
                Refresh();
            }
        }

        /// <summary>
        /// Select all
        /// </summary>
        public void SelectAll()
        {
            if (!this.IsActivated) return;

            MokkanList.SelectAll();
            Refresh();
        }

        /// <summary>
        /// Unselect 
        /// </summary>
        public void UnSelect()
        {
            if (!this.IsActivated) return;

            MokkanList.UnselectAll();
            Refresh();
        }

        /// <summary>
        /// Show property window
        /// </summary>
        public void ShowPropertyDialog()
        {
            if (MokkanList.SelectionCount == 0)
            {
                MkaPropertiesGlass frm = new MkaPropertiesGlass(_glassInfo);
                frm.ShowDialog(this);
            }
            else if (MokkanList.ShowPropertiesDialog(this))
            {
                SetDirty();
                Refresh();
            }
        }

        /// <summary>
        /// Add command to history.
        /// </summary>
        public void AddCommandToHistory(Command command)
        {
            _undoManager.AddCommandToHistory(command);

            // mokkan data changed, so raise event             
            _owner.DocAreaDataChange();
        }

        /// <summary>
        /// Clear Undo history.
        /// </summary>
        public void ClearHistory()
        {
            _undoManager.ClearHistory();
            this.Dirty = false;
        }

        /// <summary>
        /// Undo
        /// </summary>
        public void Undo()
        {
            if (!_undoManager.CanUndo)
                return;
            this.Dirty = !_undoManager.LastUndo;

            _mokkanList.UnselectAll();
            _undoManager.Undo();
            _mokkanList = _undoManager.MokkanList;
            _mokkanList.Calculate();
            Refresh();
            if (_continousPaste > 1)
                _continousPaste--;

            this.Invalidate();

            // mokkan data changed, so raise event             
            _owner.DocAreaDataChange();
        }

        /// <summary>
        /// Redo
        /// </summary>
        public void Redo()
        {
            if (!_undoManager.CanRedo)
                return;

            _mokkanList.UnselectAll();
            _undoManager.Redo();
            _mokkanList = _undoManager.MokkanList;
            _mokkanList.Calculate();
            Refresh();
            _continousPaste++;

            this.Dirty = true;
            this.Invalidate();

            // mokkan data changed, so raise event             
            _owner.DocAreaDataChange();
        }


        /// <summary>
        /// Set dirty flag (file is changed after last save operation)
        /// </summary>
        public void SetDirty()
        {
            this.Dirty = true;
        }

        /// <summary>
        /// Update document caption
        /// </summary>
        public void UpdateCaption()
        {
            if (_dirty)
                this.Text = this.FileName + "*";
            else
                this.Text = this.FileName;

            _owner.SetCaption(this.Text);
        }

        /// <summary>
        /// Right-click handler
        /// </summary>
        /// <param name="e"></param>
        private void OnContextMenu(MouseEventArgs e)
        {
            // Change current selection if necessary

            Point point = new Point(e.X, e.Y);

            int n = MokkanList.Count;
            DrawObject o = null;

            for (int i = 0; i < n; i++)
            {
                if (MokkanList[i].HitTest(point) == 0)
                {
                    o = MokkanList[i];
                    break;
                }
            }

            if (o != null)
            {
                if (!o.Selected)
                    MokkanList.UnselectAll();

                // Select clicked object
                o.Selected = true;
            }
            else
            {
                MokkanList.UnselectAll();
            }

            Refresh();      // in the case selection was changed

            _owner.MkaContextMenu.Show(this, e.Location);
        }

        /// <summary>
        /// Show remain id or not
        /// </summary>        
        public void RShow(bool showOrNot)
        {
            DrawObject.RShow = showOrNot;

            // redraw
            Invalidate();
        }

        /// <summary>
        /// Create data grid from mokkan list
        /// </summary>
        public DataGridView GetDataGrid()
        {
            DataGridView dtg = new DataGridView();
            dtg.AllowUserToAddRows = false;
            DataGridViewColumn col;
            DataGridViewRow row;

            col = new DataGridViewTextBoxColumn();
            col.HeaderText = MkaDefine.MokkanLblRBangou;
            dtg.Columns.Add(col);

            col = new DataGridViewTextBoxColumn();
            col.HeaderText = MkaDefine.MokkanLblKariShakubun;
            dtg.Columns.Add(col);

            col = new DataGridViewTextBoxColumn();
            col.HeaderText = MkaDefine.MokkanLblGaihouShoshuuJyouhou;
            dtg.Columns.Add(col);

            col = new DataGridViewTextBoxColumn();
            col.HeaderText = MkaDefine.MokkanLblShasinBangouJyouhou;
            dtg.Columns.Add(col);

            col = new DataGridViewTextBoxColumn();
            col.HeaderText = MkaDefine.MokkanLblBikou;
            dtg.Columns.Add(col);

            foreach (DrawObject o in MokkanList.MokkanObjectList)
            {
                row = new DataGridViewRow();
                row.CreateCells(dtg);
                row.Cells[0].Value = o.MokkanInfo.RBangou;
                row.Cells[1].Value = o.MokkanInfo.KariShakubun;
                row.Cells[2].Value = o.MokkanInfo.GaihouShoshuuJyouhou;
                row.Cells[3].Value = o.MokkanInfo.ShasinBangouJyouhou;
                row.Cells[4].Value = o.MokkanInfo.Bikou;
                dtg.Rows.Add(row);
            }

            return dtg;
        }

        protected override string GetPersistString()
        {
            // Add extra information into the persist string for this document
            // so that it is available when deserialized.
            return GetType().ToString() + "," + FileName + "," + Text;
        }

        #endregion

        #region IO

        /// <summary>
        /// Get image of selected mokkan to decode
        /// </summary>
        /// <returns></returns>
        public Bitmap GetMokkanToDecode(out int rid)
        {
            rid = 0;
            if (_mokkanList.SelectionCount != 1) return null;

            DrawObject obj = _mokkanList.SelectedObjects[0];
            rid = obj.MokkanInfo.RBangou;
            Bitmap img = GetImage(obj, true);

            return img;
        }

        /// <summary>
        /// Get preview image for image processing
        /// </summary>
        public Bitmap GetPreviewImage()
        {
            if (_image == null) return new Bitmap(200, 200);
            int width = Math.Max(200, _width);
            int height = Math.Max(200, _height);
            int startX = (int)(width - 200) / 2;
            int startY = (int)(height - 200) / 2;
            Rectangle cropRec = new Rectangle(startX, startY, width, height);
            Bitmap img = new Bitmap(cropRec.Width, cropRec.Height);
            Rectangle dstRec = new Rectangle(0, 0, img.Width, img.Height);
            Graphics g = Graphics.FromImage(img);
            g.DrawImage(_image, dstRec, cropRec, GraphicsUnit.Pixel);
            g.Dispose();
            return img;
        }

        /// <summary>
        /// Save mokkan file
        /// </summary>        
        public void Save(bool clear)
        {
            try
            {
                //// auto label before save
                //if (this.MokkanList.Count > 0)
                //    AutoLabel();

                // Serialize object to xml format
                XmlDocument doc = new XmlDocument();
                IXmlFormatter formatter = FepXmlableFactory.CreateXmlFormatter();
                IXmlContext cnt = FepXmlableFactory.CreateXmlContext(formatter, doc);
                doc = cnt.Document;
                XmlDeclaration xmldecl = cnt.Document.CreateXmlDeclaration("1.0", null, null);

                XmlElement _eleBat = cnt.ToXml(this.BatInfo);
                XmlElement _eleGlass = cnt.ToXml(this.GlassInfo);
                this.MokkanList.Sort();
                XmlElement _eleMk = cnt.ToXml(this.MokkanList);
                _eleGlass.AppendChild(_eleMk);
                _eleBat.AppendChild(_eleGlass);
                doc.AppendChild(_eleBat);

                // update last r bangou
                MkaMokkanInfo.LastRBangou = MokkanList.GetMaxRBangou() + 1;

                doc.InsertBefore(xmldecl, doc.DocumentElement);
                doc.Save(FileFullName);

                // save mokkan images
                if (MkaDefine.SaveMokkanImageAsSaving)
                    SaveMokkans(FileFullName);

                // register to database
                if (MkaDefine.RegisterToDbAsSaving)
                    RegisterToDb();

                if (clear)
                    ClearHistory();
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(_owner, MkaMessage.ErrSaveFile);
                _log.Error(MkaMessage.ErrSaveFile, ex);
            }
        }

        /// <summary>
        /// Save as mokkan file
        /// </summary>
        public void SaveAs()
        {
            // Get the file name
            string newFileName = FileFullName;

            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = MkaDefine.MkaFilter; ;
            sfd.InitialDirectory = Path.GetDirectoryName(newFileName);
            sfd.FileName = Path.GetFileName(newFileName);

            if (sfd.ShowDialog(_owner) != DialogResult.OK)
                return;

            newFileName = sfd.FileName;
            GlassInfo.GlassFilePath = newFileName;

            // save as glass file
            Save(true);

            // save as image file               
            String newPath = Path.GetDirectoryName(newFileName);
            String newImageName = newPath + "\\" + Path.GetFileNameWithoutExtension(newFileName) + Path.GetExtension(GlassInfo.ImageFilePath);
            File.Copy(GlassInfo.ImageFilePath, newImageName, true);
            GlassImage = newImageName;
        }

        /// <summary>
        /// Save mokkan images
        /// </summary>        
        private void SaveMokkans(String filename)
        {
            // create folder to save mokkans
            String path = Path.GetDirectoryName(filename) + "\\" + Path.GetFileNameWithoutExtension(filename);

            // if folder were existed, delete all
            if (Directory.Exists(path))
            {
                Array.ForEach(Directory.GetFiles(path), delegate(string file) { File.Delete(file); });
            }
            else
            {
                Directory.CreateDirectory(path);
            }

            Bitmap img;
            String fname;
            //StreamWriter writer;

            foreach (DrawObject obj in MokkanList.MokkanObjectList)
            {
                // save image
                img = GetImage(obj, false);
                fname = String.Format("{0}\\{1}_{2}_{3}_{4:00000}.jpg", path, BatInfo.Grid, BatInfo.BatBangou, GlassInfo.GlassItaBangou, obj.MokkanInfo.RBangou);
                img.Save(fname);
                img.Dispose();

                //// save boundary coordinates
                //if (MkaDefine.SaveMokkanBoundaryAsSaving)
                //{
                //    fname = String.Format("{0}\\{1}_{2}_{3}_{4:00000}.txt", path, BatInfo.Grid, BatInfo.BatBangou, GlassInfo.GlassItaBangou, obj.MokkanInfo.RBangou);
                //    writer = new StreamWriter(fname);
                //    writer.WriteLine(obj.Points.Count);
                //    foreach (Point p in obj.Points)
                //        writer.WriteLine("{0}\t{1}", p.X - obj.Left, p.Y - obj.Top);
                //    writer.Close();
                //}                                
            }
        }

        /// <summary>
        /// Export data to csv file
        /// </summary>
        public void ExportToCSV()
        {
            // get last accessed path
            RegistryKey key = MkaDefine.RootKey.OpenSubKey(MkaDefine.RegKey);
            String path = (String)key.GetValue(MkaDefine.RecentGlassPath);

            // save to csv file dialog
            SaveFileDialog sfd = new SaveFileDialog();
            if (Directory.Exists(path))
                sfd.InitialDirectory = path;
            sfd.Filter = MkaDefine.IOCSVFilter;
            sfd.FileName = Path.GetFileNameWithoutExtension(GlassInfo.GlassFilePath) + MkaDefine.IOCSVFileExt;

            // get file name
            if (sfd.ShowDialog() != DialogResult.OK)
                return;
            String fileName = sfd.FileName;

            // open file to write data
            StreamWriter sw = new StreamWriter(fileName, false, Encoding.GetEncoding("Shift-JIS"));

            // write glass information
            GlassInfo.ExportToCsv(sw);

            // write mokkan information' column name
            sw.WriteLine();
            sw.Write(String.Format("{0},", MkaDefine.MokkanLblRBangou));
            sw.Write(String.Format("{0},", MkaDefine.MokkanLblKariShakubun));
            sw.Write(String.Format("{0},", MkaDefine.MokkanLblGaihouShoshuuJyouhou));
            sw.Write(String.Format("{0},", MkaDefine.MokkanLblShasinBangouJyouhou));
            sw.Write(String.Format("{0}", MkaDefine.MokkanLblBikou));
            sw.WriteLine();

            // write mokkan information
            foreach (DrawObject o in MokkanList.MokkanObjectList)
                o.MokkanInfo.ExportToCsv(sw);

            // close file
            sw.Close();
        }

        /// <summary>
        /// Register annotation data to database
        /// </summary>
        public void RegisterToDb()
        {
            MkaDBConnect dbCon = new MkaDBConnect();
            int glassId = -1;
            MySqlConnection con;
            MySqlCommand cmd;

            // open connection
            if (dbCon.OpenConnection() == false)
            {
                MkaMessage.ShowError(MkaMessage.ErrDBConnect);
                return;
            }
            con = dbCon.GetConnection();

            // insert chousa, bat, glass information into database
            cmd = new MySqlCommand("insert_glass", con);
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.Add(new MySqlParameter("_chousaJisuu", GlassInfo.ChousaJisuu));
            cmd.Parameters.Add(new MySqlParameter("_ooChikuBangou", GlassInfo.OoChiku));
            cmd.Parameters.Add(new MySqlParameter("_chuushouChikuBangou", GlassInfo.ChuushouChiku));
            cmd.Parameters.Add(new MySqlParameter("_ikouBangou", GlassInfo.Ikoumei));
            cmd.Parameters.Add(new MySqlParameter("_dosouMei", GlassInfo.Dosoumei));
            cmd.Parameters.Add(new MySqlParameter("_grid", GlassInfo.Grid));
            cmd.Parameters.Add(new MySqlParameter("_date", GlassInfo.Date.ToString(MkaDefine.DBDateFormat)));
            cmd.Parameters.Add(new MySqlParameter("_batBangou", GlassInfo.BatBangou));
            cmd.Parameters.Add(new MySqlParameter("_batPath", BatInfo.BatDirectory));
            cmd.Parameters.Add(new MySqlParameter("_glassBangou", GlassInfo.GlassItaBangou));
            cmd.Parameters.Add(new MySqlParameter("_mokkanKazu", GlassInfo.MokkanKazu));
            cmd.Parameters.Add(new MySqlParameter("_kaishiRBangou", GlassInfo.KaishiRBangou));
            cmd.Parameters.Add(new MySqlParameter("_imageFileName", GlassInfo.ImageFileName));
            cmd.Parameters.Add(new MySqlParameter("_imageWidth", GlassInfo.Width));
            cmd.Parameters.Add(new MySqlParameter("_imageHeight", GlassInfo.Height));
            cmd.Parameters.Add(new MySqlParameter("_glassId", glassId));
            cmd.Parameters["_glassId"].Direction = ParameterDirection.Output;
            cmd.ExecuteNonQuery();
            glassId = (int)cmd.Parameters["_glassId"].Value;

            // insert mokkan, format, shape into database
            foreach (DrawObject mokkan in MokkanList.MokkanObjectList)
            {
                cmd = new MySqlCommand("insert_mokkan", con);
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.Add(new MySqlParameter("_rBangou", mokkan.MokkanInfo.RBangou));
                cmd.Parameters.Add(new MySqlParameter("_glassId", glassId));
                cmd.Parameters.Add(new MySqlParameter("_kariShakubun", mokkan.MokkanInfo.KariShakubun));
                cmd.Parameters.Add(new MySqlParameter("_gaihouShoshuuJyouhou", mokkan.MokkanInfo.GaihouShoshuuJyouhou));
                cmd.Parameters.Add(new MySqlParameter("_shasinBangouJyouhou", mokkan.MokkanInfo.ShasinBangouJyouhou));
                cmd.Parameters.Add(new MySqlParameter("_bikou", mokkan.MokkanInfo.Bikou));

                // add mokkan's image
                MySqlParameter param = new MySqlParameter("_image", MySqlDbType.LongBlob);
                param.Value = GetImageData(mokkan, false);
                cmd.Parameters.Add(param);

                cmd.Parameters.Add(new MySqlParameter("_borderColor", mokkan.MokkanInfo.Properties.BorderColorHtml));
                cmd.Parameters.Add(new MySqlParameter("_borderThick", mokkan.MokkanInfo.PenWidth));
                cmd.Parameters.Add(new MySqlParameter("_fillColor", mokkan.MokkanInfo.Properties.FillColorHtml));
                cmd.Parameters.Add(new MySqlParameter("_fillTransparent", mokkan.MokkanInfo.FillColorAlpha));
                cmd.Parameters.Add(new MySqlParameter("_rShowPos", (int)mokkan.MokkanInfo.RShowPosition));
                cmd.Parameters.Add(new MySqlParameter("_shapeType", mokkan.ShapeType));
                cmd.Parameters.Add(new MySqlParameter("_startX", mokkan.Left));
                cmd.Parameters.Add(new MySqlParameter("_startY", mokkan.Top));
                cmd.Parameters.Add(new MySqlParameter("_width", mokkan.Width));
                cmd.Parameters.Add(new MySqlParameter("_height", mokkan.Height));
                if (mokkan.ShapeType == 3)
                {
                    String pointStr = "";
                    foreach (Point point in mokkan.Points)
                        pointStr += "(" + point.X.ToString() + "," + point.Y.ToString() + ");";
                    pointStr = pointStr.Substring(0, pointStr.Length - 1);
                    cmd.Parameters.Add(new MySqlParameter("_coordinates", pointStr));
                }
                else
                    cmd.Parameters.Add(new MySqlParameter("_coordinates", null));
                cmd.ExecuteNonQuery();
            }

            // close connection
            dbCon.CloseConnection();
        }


        /// <summary>
        /// Get mokkan image data
        /// </summary>        
        private unsafe byte[] GetImageData(DrawObject mokkan, bool retRect)
        {
            Bitmap cropBmp = GetImage(mokkan, retRect);
            byte[] buff = (byte[])TypeDescriptor.GetConverter(cropBmp).ConvertTo(cropBmp, typeof(byte[]));
            cropBmp.Dispose();

            return buff;
        }

        /// <summary>
        /// Get bitmap from draw object
        /// </summary>        
        private Bitmap GetImage(DrawObject mokkan, bool retRect)
        {
            Rectangle cropRec = Rectangle.FromLTRB(mokkan.Left, mokkan.Top, mokkan.Right, mokkan.Bottom);
            Bitmap boundBmp, cropBmp;

            boundBmp = this.Image.Clone(cropRec, this.Image.PixelFormat);
            if (retRect || mokkan.ShapeType == 1)   // Rectangle                         
            {
                cropBmp = new Bitmap(boundBmp); ;
            }
            else if (mokkan.ShapeType == 2) // Ellipse
            {
                cropBmp = new Bitmap(cropRec.Width, cropRec.Height, PixelFormat.Format32bppArgb);
                TextureBrush tb = new TextureBrush(boundBmp);
                Graphics g = Graphics.FromImage(cropBmp);
                g.FillEllipse(tb, 0, 0, cropRec.Width, cropRec.Height);
                g.Dispose();
                tb.Dispose();
                cropBmp.MakeTransparent(Color.Black);
            }
            else   // Polygon            
            {
                cropBmp = new Bitmap(cropRec.Width, cropRec.Height, PixelFormat.Format32bppArgb);
                TextureBrush tb = new TextureBrush(boundBmp);
                Graphics g = Graphics.FromImage(cropBmp);
                g.FillRectangle(Brushes.White, cropRec);
                GraphicsPath gp = new GraphicsPath();
                Point p1, p2;
                p1 = new Point(mokkan.Points[0].X - cropRec.Left, mokkan.Points[0].Y - cropRec.Top);
                for (int i = 1; i < mokkan.Points.Count; i++)
                {
                    p2 = new Point(mokkan.Points[i].X - cropRec.Left, mokkan.Points[i].Y - cropRec.Top);
                    gp.AddLine(p1, p2);
                    p1 = p2;
                }
                g.FillPath(tb, gp);
                g.Dispose();
                tb.Dispose();
                cropBmp.MakeTransparent(Color.Black);
            }

            boundBmp.Dispose();

            return cropBmp;
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Draw graphic objects and 
        /// group selection rectangle (optionally)
        /// </summary>
        private void DocumentArea_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            Rectangle rc = ClientRectangle;

            // specifies nearest-neighbor interpolation
            g.InterpolationMode = InterpolationMode.NearestNeighbor;

            SolidBrush brush = new SolidBrush(Color.FromArgb(255, 255, 255));
            g.FillRectangle(brush, this.ClientRectangle);
            brush.Dispose();

            // zoom image size
            int zoom_width = (int)(this._width * _zoom);
            int zoom_height = (int)(this._height * _zoom);

            // start point
            int x = (rc.Width < zoom_width) ? this.AutoScrollPosition.X : 0;
            int y = (rc.Height < zoom_height) ? this.AutoScrollPosition.Y : 0;

            DrawObject.Origin = new Point(x, y);
            DrawObject.Ratio = _zoom;

            g.TranslateTransform(x, y);

            // draw image
            if (this._image != null && this._activeDisplay != DisplayType.DataOnly)
                g.DrawImage(_image, 0, 0, zoom_width, zoom_height);

            // draw boundaries
            if (this._mokkanList.Count > 0 && this._activeDisplay != DisplayType.ImageOnly)
            {
                _glassInfo.MokkanKazu = _mokkanList.Count;
                _mokkanList.Draw(g);
            }

            // If AutoRedraw is turned off, perform the drawing manually.
            if (!_inkCollectComment.AutoRedraw)
            {

                DrawStrokes(e.Graphics);

                e.Graphics.DrawRectangle(connectorPen, selectionRect);
            }

            // If the user is drawing a lasso, repaint the lasso points.
            if (InkCommentMode.PolygonSelection == inkCommentMode)
            {
                DrawLasso(e.Graphics, 0);
            }
        }

        /// <summary>
        /// Mouse down.
        /// Left button down event is passed to active tool.
        /// Right button down event is handled in this class.
        /// </summary>
        private void DocumentArea_MouseDown(object sender, MouseEventArgs e)
        {
            if (!hasMenustripChecked())
            {
                ReOpen = false;
                this.Activate();

                if (e.Button == MouseButtons.Left && _activeDisplay != DisplayType.ImageOnly)
                    tools[(int)_activeTool].OnMouseDown(this, e);
                else if (e.Button == MouseButtons.Right)
                    OnContextMenu(e);
            }
            else
            {
                //Handle event to delete stroke
                if (_owner.getToolStripMenuItem("delete"))
                {
                    if (e.Button == MouseButtons.Left)
                    {
                        Point pt = new Point(e.X, e.Y);

                        // Convert the specified point from pixel to ink space coordinates
                        _inkCollectComment.Renderer.PixelToInkSpace(this.Handle, ref pt);

                        EraseStrokes(pt, null);
                    }

                }
                // If the mouse button was pressed down within the
                // current selection area, update the application mode
                // to indicate that the user is moving ink and record
                // the starting location of the move.  This value will 
                // be used in MouseMove to determine how much the selected
                // ink should be moved.
                else
                {
                    if (selectionRect.Contains(e.X, e.Y))
                    {
                        inkCommentMode = InkCommentMode.InkMovement;

                        startMoveLocation = new Point(e.X, e.Y);
                    }
                    // Otherwise, if there is a selection and the mouse
                    // is pressed, clear the selection.
                    else if (HasSelection())
                    {
                        SetSelection(null);
                    }
                }
            }
        }

        /// <summary>
        /// Mouse move.
        /// Moving without button pressed or with left button pressed
        /// is passed to active tool.
        /// </summary>
        private void DocumentArea_MouseMove(object sender, MouseEventArgs e)
        {
            if (!hasMenustripChecked())
            {
                if (ReOpen) return;

                if ((e.Button == MouseButtons.Left || e.Button == MouseButtons.None) && _activeDisplay != DisplayType.ImageOnly)
                    tools[(int)_activeTool].OnMouseMove(this, e);
                else
                    this.Cursor = System.Windows.Forms.Cursors.Default;

                ReOpen = false;
            }
            else
            {
                //Handle event to delete stroke
                if (_owner.getToolStripMenuItem("delete"))
                {
                    if (e.Button == MouseButtons.Left)
                    {
                        Point pt = new Point(e.X, e.Y);

                        // Convert the specified point from pixel to ink space coordinates
                        _inkCollectComment.Renderer.PixelToInkSpace(this.Handle, ref pt);

                        EraseStrokes(pt, null);
                    }

                }
                else
                {

                    //Handle selection
                    // If the selected ink is currently being moved...
                    if (inkCommentMode == InkCommentMode.InkMovement && HasSelection())
                    {
                        // Compute the ink space distance the mouse has moved and
                        // move the selected strokes correspondingly.
                        Point moveAmount = new Point(e.X - startMoveLocation.X, e.Y - startMoveLocation.Y);
                        _inkCollectComment.Renderer.PixelToInkSpace(CreateGraphics(), ref moveAmount);
                        selectedStrokes.Move(moveAmount.X, moveAmount.Y);

                        // Record the location of the mouse since the next
                        // move should be relative to it.
                        startMoveLocation.X = e.X;
                        startMoveLocation.Y = e.Y;

                        // Update the selection rectangle
                        SetSelection(selectedStrokes);

                    }
                    else
                    {

                        // If the mouse has entered the rectangular selection
                        // region, disable ink collection and update the cursor
                        // to show that the user can move this region.  It is
                        // necessary to disable ink collection since ink should not
                        // flow from the pen while the user is moving the selection.
                        if (selectionRect.Contains(e.X, e.Y))
                        {
                            if (_inkCollectComment.Enabled)
                            {
                                _inkCollectComment.Enabled = false;
                                Cursor = System.Windows.Forms.Cursors.SizeAll;
                            }
                        }
                        // Otherwise, enable ink collection and set the cursor
                        // to its default value (if necessary).
                        else if (!_inkCollectComment.Enabled)
                        {
                            _inkCollectComment.Enabled = true;
                            Cursor = System.Windows.Forms.Cursors.Arrow;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Mouse up event.
        /// Left button up event is passed to active tool.
        /// </summary>
        private void DocumentArea_MouseUp(object sender, MouseEventArgs e)
        {
            if (!hasMenustripChecked())
            {
                if (e.Button == MouseButtons.Left && _activeDisplay != DisplayType.ImageOnly)
                    tools[(int)_activeTool].OnMouseUp(this, e);

                // raise select change event
                _owner.DocAreaSelectChange();

                //
                this.Controls.Remove(m_CSharpTracker);
                //Unhandle for ink move mode

                // If the user was moving selected ink and the
                // mouse is raised, set the application mode back to
                // its original value.
            }
            else
            {
                if (inkCommentMode == InkCommentMode.InkMovement)
                {
                    if (_owner.getToolStripMenuItem("select"))
                    {
                        inkCommentMode = InkCommentMode.PolygonSelection;
                    }
                    else
                    {
                        inkCommentMode = InkCommentMode.Ink;
                    }
                }
            }
        }

        #endregion Event Handlers

        #region Image Processing

        /// <summary>
        /// Auto create boundaries
        /// </summary>
        public void AutoSelect(List<DrawObject> _mokkans)
        {
            this._owner.Refresh();
            this.Refresh();
            this._owner.Cursor = System.Windows.Forms.Cursors.WaitCursor;

            CommandChange command = new CommandChange(MokkanList);

            this.MokkanList.MokkanObjectList = _mokkans;

            // rearrange remain id
            MokkanList.ReArrangeId(GlassInfo.KaishiRBangou);

            command.NewState(MokkanList);
            AddCommandToHistory(command);

            // update
            this.Invalidate();
            SetDirty();

            this._owner.Cursor = System.Windows.Forms.Cursors.Default;
        }

        /// <summary>
        /// Auto label remain id
        /// </summary>
        public void AutoLabel()
        {
            this._owner.Cursor = System.Windows.Forms.Cursors.WaitCursor;

            CommandChange command = new CommandChange(MokkanList);

            // rearrange remain id
            MokkanList.ReArrangeId(GlassInfo.KaishiRBangou);

            command.NewState(MokkanList);
            AddCommandToHistory(command);

            // redraw
            SetDirty();
            this.Invalidate();

            this._owner.Cursor = System.Windows.Forms.Cursors.Default;
        }

        /// <summary>
        /// Rearrange id
        /// </summary>
        public void Rearrange(int delta)
        {
            this._owner.Cursor = System.Windows.Forms.Cursors.WaitCursor;

            CommandChange command = new CommandChange(MokkanList);

            // rearrange remain id
            foreach (DrawObject o in MokkanList.MokkanObjectList)
                o.MokkanInfo.RBangou += delta;

            command.NewState(MokkanList);
            AddCommandToHistory(command);

            // redraw
            SetDirty();
            this.Invalidate();

            this._owner.Cursor = System.Windows.Forms.Cursors.Default;
        }

        #endregion

        /// <summary>
        /// Closing process
        /// </summary>        
        private void MkaDocument_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.WindowsShutDown) return;

            if (!_dirty)
            {
                _image.Dispose();
                _bkImg.Dispose();
                return;
            }

            String msg = String.Format(MkaMessage.InfoSaveQuestion, this.FileName);

            switch (MessageBox.Show(_owner, msg, Application.ProductName,
                MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation))
            {
                case DialogResult.Yes:
                    Save(true);
                    _image.Dispose();
                    _bkImg.Dispose();
                    break;
                case DialogResult.No:
                    _image.Dispose();
                    _bkImg.Dispose();
                    break; ;
                case DialogResult.Cancel:
                    e.Cancel = true;
                    break; ;
                default: break;
            }
        }

        /// <summary>
        /// Save document
        /// </summary>        
        private void tsmniSave_Click(object sender, EventArgs e)
        {
            this.Save(true);
        }

        /// <summary>
        /// Close document
        /// </summary>        
        private void tsmniClose_Click(object sender, EventArgs e)
        {
            this.DockHandler.Close();
        }

        private void MkaDocument_MouseClick(object sender, MouseEventArgs e)
        {
            if (_AddText)
            {
                //Remove empty richtextbox
                foreach (TransparentRichTextBox i in m_rtxtListComment)
                {
                    if (i.Text == "")
                    {
                        this.Controls.Remove(i);
                    }
                }
                m_rtxtListComment.RemoveAll(s => s.Text == "");
                TransparentRichTextBox commentTextBox = new TransparentRichTextBox();
                commentTextBox.Font = new Font("MS UI Gothic", 14);
                commentTextBox.Height = 30; //commentTextBox.Font.Height + 6;// 4 is to fit with RichTextBox
                commentTextBox.Width = 200;
                commentTextBox.BorderStyle = BorderStyle.None;
                commentTextBox.MouseDown += new MouseEventHandler(richText_MouseDown);
                commentTextBox.SelectionChanged += new EventHandler(richText_ChangeSellect);
                commentTextBox.GotFocus += new EventHandler(richText_GotFocus);
                //commentTextBox.TextChanged += new EventHandler(richText_TextChanged);
                commentTextBox.Location = new Point(e.X, e.Y);
                this.Controls.Add(commentTextBox);
                commentTextBox.Focus();
                m_rtxtListComment.Add(commentTextBox);
            }
        }

        //Richtext box textchanged event
        private void richText_TextChanged(object sender, EventArgs e)
        {
            TransparentRichTextBox rtxBox = sender as TransparentRichTextBox;
            int index = rtxBox.SelectionStart;
            int line = rtxBox.GetLineFromCharIndex(index);

            String measureString = rtxBox.Lines[line];
            Size size = TextRenderer.MeasureText(measureString, rtxBox.Font);
            if (rtxBox.Width < (size.Width + 10))
                rtxBox.Width = size.Width + 10;
            if ((size.Width + rtxBox.Location.X) > (this.Width - 30))
            {
                rtxBox.Text = rtxBox.Text.Insert(index, Environment.NewLine);
                rtxBox.Height = rtxBox.Height + size.Height + 4;
                rtxBox.SelectionStart = index + 1;
            }
            if (this.Controls.Contains(m_CSharpTracker))
            {
                this.Controls.Remove(m_CSharpTracker);
                m_CSharpTracker = new Tracker(rtxBox);

                this.Controls.Add(m_CSharpTracker);
                m_CSharpTracker.BringToFront();
                m_CSharpTracker.Draw();
            }
        }
        //Customize event mouse down for added richtext 
        private void richText_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            TransparentRichTextBox rtxBox = sender as TransparentRichTextBox;
            rtxBox.BringToFront();

            rtxBox.Capture = false;
            if (this.Controls.Contains(m_CSharpTracker))
                this.Controls.Remove(m_CSharpTracker);
            m_CSharpTracker = new Tracker(rtxBox);

            this.Controls.Add(m_CSharpTracker);
            m_CSharpTracker.BringToFront();
            m_CSharpTracker.Draw();
        }
        //Customize event mouse down for added ink edit 
        private void inkPicture_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            InkPicture inkComment = sender as InkPicture;
            inkComment.BringToFront();

            inkComment.Capture = false;
            if (this.Controls.Contains(m_CSharpTracker))
                this.Controls.Remove(m_CSharpTracker);
            //CSharpTracker = new Tracker((Control)inkComment);

            this.Controls.Add(m_CSharpTracker);
            m_CSharpTracker.BringToFront();
            m_CSharpTracker.Draw();
        }
        private void richText_GotFocus(object sender, EventArgs e)
        {
            LastTextBoxFocused = (TransparentRichTextBox)sender;

        }

        private void richText_ChangeSellect(object sender, EventArgs e)
        {
            StartPositionSelectedText = LastTextBoxFocused.SelectionStart;
            LengthSelectedText = LastTextBoxFocused.SelectionLength;
        }
        private void MkaDocument_FormClosed(object sender, FormClosedEventArgs e)
        {
            FormSerialisor.Serialise(this.m_rtxtListComment, Application.StartupPath + "\\" + this.Text.Substring(0, 6) + ".xml");
        }

        private void MkaDocument_Load(object sender, EventArgs e)
        {
            m_rtxtListComment = FormSerialisor.Deserialise(Application.StartupPath + "\\" + this.Text.Substring(0, 6) + ".xml");
            foreach (TransparentRichTextBox n in m_rtxtListComment)
            {
                n.Enabled = false;
                this.Controls.Add(n);
                n.MouseDown += new MouseEventHandler(richText_MouseDown);
                n.GotFocus += new EventHandler(richText_GotFocus);
                n.SelectionChanged += new EventHandler(richText_ChangeSellect);
            }
            // Create a new ink collector and assign it to this form's window
            _inkCollectComment = new InkCollector(this.Handle);

            // Set the ink collector's pen width
            _inkCollectComment.DefaultDrawingAttributes.Width = MediumInkWidth;

        }

        /// <summary>
        /// Helper method that performs a hit test using the specified point.
        /// It deletes all strokes that were hit by the point
        /// </summary>
        /// <param name="pt">The point to use for hit testing</param>
        private void EraseStrokes(Point pt, Stroke currentStroke)
        {

            // Use HitTest to find the collection of strokes that are intersected
            // by the point.  The HitTestRadius constant is used to specify the 
            // radius of the hit test circle in ink space coordinates (1 unit = .01mm).
            Strokes strokesHit = _inkCollectComment.Ink.HitTest(pt, HitTestRadius);

            if (strokesHit.Count > 0)
            {
                Ink temp = new Ink();
                // Delete all strokes that were hit by the point
                temp.AddStrokesAtRectangle(strokesHit, strokesHit.GetBoundingBox());
                _inkCollectComment.Ink.DeleteStrokes(strokesHit);
                m_inkForDeletedStrokes.Push(temp);
                // R_inkCollectCommentto reflect the change
                this.Refresh();
            }
        }
        /// <summary>
        /// Draws the selection lasso.
        /// 
        /// Note that this method does NOT draw a point for every piece
        /// of packet data.  Instead, it draws evenly spaced dots that
        /// fall along the lasso path.
        /// </summary>
        /// <param name="g">The graphics device</param>
        /// <param name="newPacketIndex">The index where the new packets begin</param>
        public void DrawLasso(Graphics g, int newPacketIndex)
        {

            // The distance between the current point and the next point
            int dx, dy;

            // The distance and angle of the line connecting the current 
            // point and the next point
            double lineLength;
            double angle;

            // The horizontal and vertical spacing between the dots
            double segSpaceX, segSpaceY;

            // The total number of dots to draw
            int totalSegments;

            // Undraw the line that connected the first point to the 
            // last point before the latest packets were added.
            DrawLassoConnector(0, newPacketIndex - 1);

            // For each lasso point, draw the corresponding lasso dots.
            // Note that this method does NOT draw a point for every piece
            // of packet data.  Instead, it draws evenly spaced dots that
            // fall along the lasso path.
            for (int i = newPacketIndex; i < lassoPoints.Count; i++)
            {
                //  Always draw the first packet...
                if (0 == i)
                {
                    // Update the last drawn lasso dot to this packet
                    lastDrawnLassoDot.X = ((Point)lassoPoints[i]).X;
                    lastDrawnLassoDot.Y = ((Point)lassoPoints[i]).Y;

                    // use a helper method to draw the lasso dot
                    DrawSelectionInkDot(g, lastDrawnLassoDot.X, lastDrawnLassoDot.Y);
                }
                else
                {
                    // Compute the x and y distance between this point and the last drawn
                    // lasso dot
                    dx = ((Point)lassoPoints[i]).X - lastDrawnLassoDot.X;
                    dy = ((Point)lassoPoints[i]).Y - lastDrawnLassoDot.Y;

                    // Compute length of the line between this point and the last drawn
                    // lasso dot
                    lineLength = Math.Sqrt(dx * dx + dy * dy);

                    // If the spacing between this packet and the last drawn lasso
                    // dot is greater than the desired DotSpacing, draw as many
                    // evently spaced lasso points as needed to fill the distance...
                    if (DotSpacing <= lineLength)
                    {

                        // Calculate the angle of the line connecting this point 
                        // to the last drawn lasso point. 
                        angle = Math.Atan2(dy, dx);

                        // Calculate the x and y components of the dot spacing
                        segSpaceX = DotSpacing * Math.Cos(angle);
                        segSpaceY = DotSpacing * Math.Sin(angle);

                        // Calculate the number of dots we will need to draw.
                        totalSegments = (int)(lineLength / (double)DotSpacing);

                        // draw the lasso dots...
                        for (int j = 0; j < totalSegments; j++)
                        {
                            // The coordinates of the lasso dot are determined by the
                            // previous lasso dot plus the x and y components of the
                            // dot spacing (computed above).
                            lastDrawnLassoDot.X = (int)(lastDrawnLassoDot.X + segSpaceX);
                            lastDrawnLassoDot.Y = (int)(lastDrawnLassoDot.Y + segSpaceY);

                            // use a helper method to draw the lasso dot
                            DrawSelectionInkDot(g, lastDrawnLassoDot.X, lastDrawnLassoDot.Y);

                        }
                    }
                }
            }

            // draw the line connecting the first point to the last point
            DrawLassoConnector(0, lassoPoints.Count - 1);
        }
        /// <summary>
        /// Helper method to draw/undraw the lasso connector line
        /// </summary>
        /// <param name="start">The index of the start point</param>
        /// <param name="end">The index of the end point</param>
        /// <param name="points">The lasso points</param>
        private void DrawLassoConnector(int start, int end)
        {
            if ((end > start) && (lassoPoints.Count > 1) && (end < lassoPoints.Count))
            {
                // Draw a reversible line from the point at start
                // to the point at end.
                Point startPoint = (Point)lassoPoints[start];
                Point endPoint = (Point)lassoPoints[end];

                // Convert to screen space
                startPoint = PointToScreen(startPoint);
                if (mPreviousPoint != Point.Empty)
                {
                    // Clear last line drawn
                    ControlPaint.DrawReversibleLine(startPoint, mPreviousPoint, BackColor);
                }
                mPreviousPoint = endPoint = PointToScreen(endPoint);

                // Reverse the line - this is the .NET way of drawing
                // an XOR line.

                ControlPaint.DrawReversibleLine(startPoint, endPoint, BackColor);
            }
        }
        /// <summary>
        /// Helper method to draw a lasso seletion dot
        /// </summary>
        /// <param name="g">The graphics device</param>
        /// <param name="x">The x coordinate of the center of the dot</param>
        /// <param name="y">The y coordinate of the center of the dot</param>
        private void DrawSelectionInkDot(Graphics g, int x, int y)
        {
            //
            // Offset the x and y by 1/2 the dot size (biasing lower-right)
            //
            x = x - (DotSize / 2);
            y = y - (DotSize / 2);

            // Draw the inside of the lasso dot
            g.FillEllipse(dotPen.Brush, x, y, DotSize, DotSize);

            // Draw the outside edge of the lasso dot
            g.DrawEllipse(dotEdgePen, x, y, DotSize, DotSize);

        }
        /// <summary>
        /// This method is used to render ink when there is
        /// a selection.
        /// </summary>
        /// <param name="g">The graphics device</param>
        private void DrawStrokes(Graphics g)
        {

            // First, draw the strokes that are not part of the 
            // selection.  These strokes will appear the same
            // as the InkCollector would normally draw them.
            Strokes unselectedStrokes = _inkCollectComment.Ink.Strokes;
            unselectedStrokes.Remove(selectedStrokes);
            _inkCollectComment.Renderer.Draw(g, unselectedStrokes);

            // Next, draw each selected stroke.  A selected stroke
            // is rendered in white with a selection border.
            foreach (Stroke selectedStroke in selectedStrokes)
            {
                DrawingAttributes da = selectedStroke.DrawingAttributes.Clone();
                da.Color = SystemColors.WindowText;
                da.Width = da.Width + SelectedInkWidthIncrease;
                _inkCollectComment.Renderer.Draw(g, selectedStroke, da);
                da.Color = Color.White;
                da.Width = da.Width - SelectedInkWidthIncrease;
                _inkCollectComment.Renderer.Draw(g, selectedStroke, da);
            }
        }
        /// <summary>
        /// Event Handler from Ink Collector's Stroke event
        /// 
        /// This event is fired when a new lasso stroke is drawn.  
        /// In this case, it is necessary to update the selected
        /// strokes information.
        /// </summary>
        /// <param name="sender">The control that raised the event.</param>
        /// <param name="e">The event arguments.</param>
        private void myInkCollector_Stroke(object sender, InkCollectorStrokeEventArgs e)
        {

            // This stroke corresponds to the lasso - 
            // cancel it so that it is not added into the ink
            e.Cancel = true;

            Strokes hitStrokes = null;

            // If there are enough lasso points, perform a hit test
            // to determine which strokes were selected. 
            if (lassoPoints.Count > 2)
            {

                // Convert the lasso points from pixels to ink space
                Point[] inkLassoPoints = (Point[])lassoPoints.ToArray(typeof(Point));
                _inkCollectComment.Renderer.PixelToInkSpace(CreateGraphics(), ref inkLassoPoints);

                // Perform a hit test on this ink collector's ink to
                // determine which points were selected by the lasso stroke.
                //
                // Note that there is a slight inefficiency here since the
                // lasso stroke is part of the ink and, therefore, part of the
                // hit test - even though we don't need it.   It would have 
                // been more efficient to remove the stroke from the ink before 
                // calling HitTest.  However, it is not good practice to modify 
                // the stroke inside of its own event handler.
                hitStrokes = _inkCollectComment.Ink.HitTest(inkLassoPoints, LassoPercent);
                hitStrokes.Remove(e.Stroke);

            }

            // Reset the lasso points
            lassoPoints.Clear();
            lastDrawnLassoDot = Point.Empty;
            mPreviousPoint = Point.Empty;

            // Use helper method to set the selection
            SetSelection(hitStrokes);

        }
        // --------------- Ink Collector Events ---------------

        /// <summary>
        /// Event Handler from Ink Collector's NewPackets event
        /// 
        /// This event is fired when the Ink Collector receives 
        /// new packet data and the user is drawing a lasso.  
        /// In this case,  it is necessary to intercept the new packets
        /// and use them to draw the selection lasso.
        /// </summary>
        /// <param name="sender">The control that raised the event.</param>
        /// <param name="e">The event arguments.</param>
        private void myInkCollector_NewPackets(object sender, InkCollectorNewPacketsEventArgs e)
        {

            // retrieve the size of each packet
            int packetSize = e.Stroke.PacketSize;

            // the index where the new lasso points will be added
            int newPacketIndex = lassoPoints.Count;

            // Add each new packet into the lasso points collection
            for (int i = 0; i < e.PacketCount; i++)
            {

                // retrieve the x and y packet values 
                Point pt = new Point(e.PacketData[i * packetSize + XPacketIndex],
                    e.PacketData[i * packetSize + YPacketIndex]);
                _inkCollectComment.Renderer.InkSpaceToPixel(this.Handle, ref pt);


                // If the x or y packet values fall outside of
                // the drawing area , update them to the nearest
                // location on the drawing area.  This adjustment
                // prevents the lasso's boundaries from going 
                // beyond the drawing area.
                if (pt.X < 0)
                {
                    pt.X = 0;
                }
                if (pt.X > ClientSize.Width)
                {
                    pt.X = ClientSize.Width;
                }
                if (pt.Y < 0)
                {
                    pt.Y = 0;
                }
                if (pt.Y > this.ClientSize.Height)
                {
                    pt.Y = ClientSize.Height;
                }

                // Add the new point into the lasso points collection
                lassoPoints.Add(pt);

            }

            // Draw the updated lasso.  In order to improve performance,
            // only the new lasso packets will be drawn.
            DrawLasso(CreateGraphics(), newPacketIndex);
        }
        /// <summary>
        /// Sets the selected strokes and selection rectangle.
        /// </summary>
        /// <param name="strokes">The strokes that should be selected.  If null, the selection becomes empty</param>
        private void SetSelection(Strokes strokes)
        {
            // Tracks whether the rectangle that bounds the selected
            // strokes should be displayed
            bool isSelectionVisible = false;

            // Update the selected strokes collection
            selectedStrokes = strokes;

            // If no strokes are selected, set the selection rectangle
            // to empty
            if (!HasSelection())
            {
                selectionRect = Rectangle.Empty;
            }
            // Otherwise, at least one stroke is selected and it is necessary
            // to display the selection rectangle.
            else
            {
                isSelectionVisible = true;

                // Retrieve the bounding box of the strokes
                selectionRect = selectedStrokes.GetBoundingBox();
                InkSpaceToPixel(CreateGraphics(), ref selectionRect);

                // Pad the selection rectangle so that the selected ink 
                // doesn't overlap with the selection rectangle's handles.
                selectionRect.Inflate(SelectionRectBuffer, SelectionRectBuffer);

                // compute the center of the rectangle that bounds the 
                // selected strokes
                int xAvg = (selectionRect.Right + selectionRect.Left) / 2;
                int yAvg = (selectionRect.Top + selectionRect.Bottom) / 2;

                // Draw the resize handles
                // top left
                SetLocation(selectionHandles[0], selectionRect.Left, selectionRect.Top);
                // top
                SetLocation(selectionHandles[1], xAvg, selectionRect.Top);
                // top right 
                SetLocation(selectionHandles[2], selectionRect.Right, selectionRect.Top);

                // left 
                SetLocation(selectionHandles[3], selectionRect.Left, yAvg);
                // right
                SetLocation(selectionHandles[4], selectionRect.Right, yAvg);

                // bottom left
                SetLocation(selectionHandles[5], selectionRect.Left, selectionRect.Bottom);
                // bottom
                SetLocation(selectionHandles[6], xAvg, selectionRect.Bottom);
                // bottom right
                SetLocation(selectionHandles[7], selectionRect.Right, selectionRect.Bottom);
            }

            // Set the visibility of each selection handle in the 
            // selection rectangle.  If there is no selection, all 
            // handles should be hidden.  Otherwise, all handles should
            // be visible.
            foreach (PictureBox pb in selectionHandles)
            {
                pb.Visible = isSelectionVisible;
            }

            // Turn off autoredrawing if there is a selection - otherwise,
            // the selected ink will not be displayed as selected.
            _inkCollectComment.AutoRedraw = !isSelectionVisible;

            // Since the selection has changed, repaint the screen.
            Refresh();
        }

        /// <summary>
        /// Helper method to set the location of the selection rectangle
        /// handle.
        /// </summary>
        /// <param name="pb">The handle's picture box</param>
        /// <param name="xCenter">The desired x coordinate of the center</param>
        /// <param name="yCenter">The desired y coordinate of the center</param>
        public void SetLocation(PictureBox pb, int xCenter, int yCenter)
        {
            Point location = new Point();

            location.X = xCenter - pb.Width / 2;
            location.Y = yCenter - pb.Height / 2;

            pb.Location = location;
        }

        /// <summary>
        /// Helper method to determine if there is a selection
        /// </summary>
        /// <returns>True if there is a selection</returns>
        public bool HasSelection()
        {
            return selectedStrokes != null && selectedStrokes.Count > 0;
        }
        /// <summary>
        /// Helper method to convert a rectangle in ink space
        /// coordinates to pixel coordinates.  (1 ink space unit = .01mm)
        /// 
        /// Note that this method works since there is guaranteed not
        /// to be any rotation in this sample.
        /// </summary>
        /// <param name="g">The graphics display</param>
        /// <param name="r">The rectangle to convert</param>
        private void InkSpaceToPixel(Graphics g, ref Rectangle r)
        {
            Point leftTop = new Point(r.X, r.Y);
            Point widthHeight = new Point(r.Width, r.Height);
            _inkCollectComment.Renderer.InkSpaceToPixel(g, ref leftTop);
            _inkCollectComment.Renderer.InkSpaceToPixel(g, ref widthHeight);

            r.Location = leftTop;
            r.Size = new Size(widthHeight);

        }

        /// <summary>
        /// Check if have any item in menu strip is checked
        /// </summary>
        /// <returns>if have return true, on the other hand return false</returns>
        private bool hasMenustripChecked()
        {
            bool hasChecked = false;
            hasChecked = (_owner.getToolStripMenuItem("ink") ||
                _owner.getToolStripMenuItem("select")
                || _owner.getToolStripMenuItem("copy")
                || _owner.getToolStripMenuItem("paste")
                || _owner.getToolStripMenuItem("cut")
                || _owner.getToolStripMenuItem("delete"));
            return hasChecked;
        }
        /// <summary>
        /// This method uses the Ink API to copy ink onto
        /// the clipboard.
        /// </summary>
        /// <param name="clipboardModes">The clipboard modes (such as copy or paste)</param>
        private void CopyInkToClipboard(InkClipboardModes clipboardModes)
        {

            // Declare the ink clipboard formats to put on the clipboard
            InkClipboardFormats formats = new InkClipboardFormats();
            formats |= InkClipboardFormats.TextInk;


            // If at least one format was selected, invoke the Ink
            // API's ClipboardCopy method.  Note that selectedStrokes
            // could be null, but that this is ok - if selectedStrokes
            // is null, all of the ink is copied.

            if (clipboardModes == InkClipboardModes.Cut)
            {
                Ink temp = new Ink();
                temp.AddStrokesAtRectangle(selectedStrokes, selectedStrokes.GetBoundingBox());
                m_inkForDeletedStrokes.Push(temp);
            }
            _inkCollectComment.Ink.ClipboardCopy(selectedStrokes, formats, clipboardModes);

        }

        /// <summary>
        /// Handle ink collection when ink toolstrip menue is clicked
        /// </summary>
        public void inkMenuItem_Click()
        {
            // Set the application mode to ink collection
            inkCommentMode = InkCommentMode.Ink;

            // Ink strokes should be opaque
            _inkCollectComment.DefaultDrawingAttributes.Transparency = 0;

            // Use helper method to clear the selection
            SetSelection(null);

            // Unhook the new packets and stroke events since
            // these events are only needed to implement lasso selection.
            // These events are only hooked when they are needed to improve
            // performance.
            if (eventCheck == 1)
            {
                _inkCollectComment.NewPackets -= new InkCollectorNewPacketsEventHandler(myInkCollector_NewPackets);
                _inkCollectComment.Stroke -= new InkCollectorStrokeEventHandler(myInkCollector_Stroke);
                eventCheck = 0;
            }
        }

        /// <summary>
        /// Handle ink collection when select toolstrip menue is clicked
        /// </summary>
        public void selectMenuItem_Click()
        {
            // Set the application mode to lasso selection
            inkCommentMode = InkCommentMode.PolygonSelection;

            // Lasso strokes should be transparent 
            _inkCollectComment.DefaultDrawingAttributes.Transparency = 255;

            // Use helper method to clear the selection
            SetSelection(null);

            // Hook the new packets and stroke events since
            // these events are needed to implement lasso selection.
            // These events are only hooked when they are needed to improve
            // performance.
            // Sometimes user try to click this button many times, eventcheck variable to make sure that
            // they can not add more than one time
            if (eventCheck < 1)
            {
                _inkCollectComment.NewPackets += new InkCollectorNewPacketsEventHandler(myInkCollector_NewPackets);
                _inkCollectComment.Stroke += new InkCollectorStrokeEventHandler(myInkCollector_Stroke);
                eventCheck = 1;//one means that they are added one time
            }
        }
        private void updateEventHandler()
        {

        }
        /// <summary>
        /// Handle ink collection when delete toolstrip menue is clicked
        /// </summary>
        public void deleteMenuItem_Click()
        {
            inkCommentMode = InkCommentMode.DeleteStroke;
            SetSelection(null);
            //Event for select should be removed if it is existing 
            if (eventCheck == 1)
            {
                _inkCollectComment.NewPackets -= new InkCollectorNewPacketsEventHandler(myInkCollector_NewPackets);
                _inkCollectComment.Stroke -= new InkCollectorStrokeEventHandler(myInkCollector_Stroke);
                eventCheck = 0;// They are not added
            }
        }
        /// <summary>
        /// Handle ink collection when copy toolstrip menue is clicked
        /// </summary>
        public void copyMenuItem_Click()
        {
            // Use helper method to copy the selection
            CopyInkToClipboard(InkClipboardModes.Copy);
        }
        /// <summary>
        /// Handle ink collection when cut toolstrip menue is clicked
        /// </summary>
        public void cutMenuItem_Click()
        {
            // Use helper method to cut the selection
            CopyInkToClipboard(InkClipboardModes.Cut);
            SetSelection(null);
        }
        /// <summary>
        /// Handle ink collection when Paste toolstrip menue is clicked
        /// </summary>
        public void pasteMenuItem_Click()
        {
            if (_inkCollectComment.Ink.CanPaste())
            {
                // Compute the location where the ink should be pasted;
                // this location should be shifted from the origin
                // to account for the width of the selection rectangle's handle.
                Point offset = new Point(leftTopHandle.Width + 1, leftTopHandle.Height + 1);
                _inkCollectComment.Renderer.PixelToInkSpace(CreateGraphics(), ref offset);

                // Use Ink API to paste the clipboard data into the Ink
                Strokes pastedStrokes = _inkCollectComment.Ink.ClipboardPaste(offset);

                // If the contents of the clipboard were a valid format 
                // (Ink Serialized Format or Embeddable OLE Object) and at
                // least one stroke was pasted into the ink, use a helper 
                // method to update the stroke selection.  Otherwise,
                // the result will be null and this paste becomes a no-op.  
                if (null != pastedStrokes)
                {
                    SetSelection(pastedStrokes);
                }
            }
        }
        /// <summary>
        /// Handle ink collection when Paste toolstrip menue is clicked
        /// </summary>
        public void undoMenuItem_Click()
        {
            if (m_inkForDeletedStrokes.Count > 0)
            {
                Ink temp = m_inkForDeletedStrokes.Pop();
                _inkCollectComment.Ink.AddStrokesAtRectangle(temp.Strokes, temp.Strokes.GetBoundingBox());
                Refresh();
            }
        }

        private void zoomInkUpdate()
        {
            // Create a new transformation matrix
            Matrix m = new Matrix();

            // Apply the current scale factor
            m.Scale(this._zoom, this._zoom);

            m.Translate(-(HorizontalScroll.Value * _image.Width * 26.5f / HorizontalScroll.Maximum), -(VerticalScroll.Value * _image.Height * 26.5f / VerticalScroll.Maximum));
            _inkCollectComment.Renderer.SetObjectTransform(m);
            Refresh();
        }

        private void scroll_EventHandler(object sender, ScrollEventArgs e)
        {
            zoomInkUpdate();
        }
        private void scroll_MouseWheel(object sender, MouseEventArgs e)
        {
            zoomInkUpdate();
        }
    }
}
